/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-27     zylx         first version
 */

#include "board.h"
#include "drv_qspi.h"
#include "drv_config.h"

#ifdef RT_USING_QSPI

#define DBG_ENABLE
#define DBG_LEVEL                           DBG_INFO
#define DRV_DEBUG
#define LOG_TAG              "drv.qspi"
#include <drv_log.h>

#if defined(BSP_USING_QSPI)

static int mcu_qspi_init(void)
{
    int result = RT_EOK;

    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_XSPI, ENABLE);    // Enable xSPI
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO,   ENABLE);
    RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOE, ENABLE);  //GPIOE clk enable

    GPIO_InitType GPIO_InitStructure;

    /* Initialize GPIO_InitStructure */
    GPIO_InitStruct(&GPIO_InitStructure);
          
    /* Confugure NSS0 pins */   
    GPIO_InitStructure.Pin       = GPIO_PIN_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Slew_Rate = GPIO_SR_SLOW_SLEW;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF7;
    GPIO_InitStructure.GPIO_Current = GPIO_DC_12mA;
    GPIO_InitPeripheral(GPIOE, &GPIO_InitStructure);
            
    /* Confugure SCK pin  */
    GPIO_InitStructure.Pin       = GPIO_PIN_10;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF7;
    GPIO_InitPeripheral(GPIOE, &GPIO_InitStructure);
    
    /* Confugure IO0\IO1\IO2\IO3 pin  */
    GPIO_InitStructure.Pin       = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF7;
    GPIO_InitPeripheral(GPIOE, &GPIO_InitStructure);

    uint8_t initStatus = SpiFlash_initialize();

    if (initStatus != RT_EOK) {
        LOG_E("xSpi init fault\r\n");
    } else {
        LOG_I("xSpi init success\r\n");
    }

    return result;
}


/**
 * Write data to flash.
 * @note This operation's units is word.
 * @note This operation must after erase. @see flash_erase.
 *
 * @param addr flash address
 * @param buf the write data buffer
 * @param size write bytes size
 *
 * @return result
 */
int NandFlash_write(rt_uint32_t addr, const rt_uint8_t *buf, size_t size)
{
    if (size < 1)
    {
        return -RT_EINVAL;
    }

    uint8_t ret = SpiFlash_QuadWriteByte(addr, size, (uint8_t *)buf);

    if ((ret & 0x08) != 0) {
        LOG_E("FATFS: Bloack<%d> write error, code %d\r\n", addr, size);
        return -1;
    }
    
    return size;
}

/**
 * Read data from flash.
 * @note This operation's units is word.
 *
 * @param addr flash address
 * @param buf buffer to store read data
 * @param size read bytes size
 *
 * @return result
 */
int NandFlash_read(rt_uint32_t addr, rt_uint8_t *buf, size_t size)
{
    uint8_t newStatus = 0;
    newStatus = SpiFlash_QuadReadByte(addr, size, (uint8_t *)buf);
    if ((newStatus & 0x30) != 0x00) {
        LOG_E("FATFS: <%d> read error, code %d\r\n", addr, newStatus);
        return -1;
    }

    return size;
}

int NandFlash_erase(rt_uint32_t addr, size_t size)
{
    uint8_t newStatus = 0;

    uint32_t blockPageStart = ( (addr/FLASH_PAGESIZE) / 64) * 64;
    uint32_t blockPageEnd   = ( ((addr + size - 1)/FLASH_PAGESIZE) / 64) * 64;
    for (uint32_t block = blockPageStart; block <= blockPageEnd;) {
        newStatus = SpiFlash_BlockErase128K(block);
        if ((newStatus&0x04) != 0x00) {
            LOG_E("FATFS: Bloack<%d> erase error, code %d\r\n", block, newStatus);
            return -1;
        }
        block += 64;
    }

    return size;
}

static int rt_hw_qspi_bus_init(void)
{
    return mcu_qspi_init();
}
INIT_BOARD_EXPORT(rt_hw_qspi_bus_init);

#endif /* BSP_USING_QSPI */
#endif /* RT_USING_QSPI */
